{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "Create by 2018-05-22\n",
    "\n",
    "@author: 代码来源于网上，书上代码有误\n",
    "\"\"\"\n",
    "from numpy import *\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载数据集\n",
    "def loadDataSet(fileName):\n",
    "    # 数据矩阵\n",
    "    dataMat = []\n",
    "\n",
    "    # 标签向量\n",
    "    labelMat = []\n",
    "\n",
    "    fr = open(fileName)\n",
    "    for line in fr.readlines():\n",
    "        # strip()表示删除空白符，split()表示分割\n",
    "        lineArr = line.strip().split('\\t')\n",
    "        dataMat.append([float(lineArr[0]), float(lineArr[1])])  # 1.0表示x0\n",
    "        labelMat.append(float(lineArr[2]))\n",
    "    return dataMat, labelMat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "def showDataSet(dataMat, labelMat):\n",
    "    data_plus = []                                  #正样本\n",
    "    data_minus = []                                 #负样本\n",
    "    for i in range(len(dataMat)):\n",
    "        if labelMat[i] > 0:\n",
    "            data_plus.append(dataMat[i])\n",
    "        else:\n",
    "            data_minus.append(dataMat[i])\n",
    "    data_plus_np = np.array(data_plus)              #转换为numpy矩阵\n",
    "    data_minus_np = np.array(data_minus)            #转换为numpy矩阵\n",
    "    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1])   #正样本散点图\n",
    "    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #负样本散点图\n",
    "    plt.show()\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(100, 2)\n",
      "(100,)\n"
     ]
    }
   ],
   "source": [
    "dataMat, labelMat=loadDataSet('testSet.txt')\n",
    "print(np.array(dataMat).shape)\n",
    "\n",
    "print(np.array(labelMat).shape)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "showDataSet(dataMat, labelMat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "#功能：在(0, m)的区间范围内随机选择一个除i以外的整数\n",
    "#i;第一个alpha索引\n",
    "#m：数据总的个数\n",
    "#j：（0，m）中除i以外的数\n",
    "def selectJrand(i, m):\n",
    "    j = i\n",
    "    while (j == i):\n",
    "        j = int (random.uniform(0, m))\n",
    "    return j"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "#修剪函数，看有没有超出函数界\n",
    "def clipAlpha(aj, H, L):\n",
    "    if aj > H:\n",
    "        aj = H\n",
    "    if L > aj:\n",
    "        aj = L\n",
    "    return aj"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "\"\"\"\n",
    "伪代码大致如下：\n",
    "\n",
    "创建一个α向量并向其初始化为0向量\n",
    "\n",
    "当迭代次数小于最大迭代次数时（外循环）\n",
    "\n",
    "     对数据集中的每个数据向量（内循环）：\n",
    "\n",
    "          如果该向量可以被优化：\n",
    "\n",
    "               随机选择另一个数据向量\n",
    "\n",
    "               同时优化这两个向量\n",
    "\n",
    "               如果两个向量都不能被优化，推出内循环\n",
    "\n",
    "     如果所有向量都没被优化，增加迭代次数，继续下一次循环\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "#简化版的smo算法\n",
    "#具体的步骤看笔记一共八个步骤\n",
    "def smoSimple(dataMatIn, classLabels, C, toler, maxIter):\n",
    "    '''\n",
    "    输入参数：数据集，类别标签，常数C：松弛变量，toler：容错率， maxIter：最大循环的次数\n",
    "    '''\n",
    "    #将输入参数转化为numpy矩阵\n",
    "    dataMatrix = mat(dataMatIn)\n",
    "    #标签为列向量，这样标签中的每行元素就和数据矩阵中的行一一对应了,之前是100*1，转换后为1*100\n",
    "    labelMat = mat(classLabels).T\n",
    "    #初始化b参数\n",
    "    b = 0\n",
    "    # m,n=100,2\n",
    "    m,n = shape(dataMatrix)\n",
    "    #构建一个alpha列矩阵，设为0\n",
    "    alphas = mat(zeros((m,1)))\n",
    "    #用于存储在没有任何alpha改变的情况下遍历数据集的次数。当该变量到达输入值maxIter时，函数结束运行并退出\n",
    "    #初始化迭代次数\n",
    "    iter = 0\n",
    "    #开始循环\n",
    "    #只有在所有数据集遍历maxIter次数之后且不再发生任何alpha修改后，程序才会退出循环\n",
    "    while(iter < maxIter):\n",
    "        #先设为0，用于记录alpha是否已经进行优化\n",
    "        #初始化alpha优化次数\n",
    "        alphaPairsChanged = 0\n",
    "        for i in range(m):\n",
    "            #fXi能够倍计算出来，这就是我们预测的类别\n",
    "            #alphas：列矩阵100*1,labelMat:100*1,\n",
    "            #multiply(alphas,labelMat).T:1*100\n",
    "            #dataMatrix:100*2\n",
    "            #dataMatrix[i,:]：2*1\n",
    "            #multiply:矩阵对应位置相乘\n",
    "            #步骤1：计算误差Ei\n",
    "            fXi = float(multiply(alphas,labelMat).T*(dataMatrix*(dataMatrix[i,:]).T))+b\n",
    "            #基于实例的预测结果和真实结果对比计算误差Ei\n",
    "            Ei = fXi - float(labelMat[i])\n",
    "            '''\n",
    "            如果误差很大，那么可以对该数据实例所对应的alpha值进行优化\n",
    "            在if的判断中: 不管是正间隔还是负间隔都会被测试，同时还要检测alpha值不能等于0或C\n",
    "            因为后面alpha的值小于0或大于C时将被调整为0或C，所以一旦alpha为0或C,\n",
    "            那么它们就在边界上了，因而不能够再增大或减小，因此也就不值得对它们进行优化了\n",
    "            '''\n",
    "            #优化alpha，设定容错率\n",
    "            #如果该数据向量可以被优化\n",
    "            if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler)and (alphas[i]>0)):\n",
    "                #利用辅助函数随机选择第二个alpha值\n",
    "                #随机选择一个alpha_i成对优化的alpha_j\n",
    "                j = selectJrand(i, m)\n",
    "                #计算选择的第二个alpha的误差\n",
    "                #步骤1：计算误差Ei\n",
    "                fXj = float(multiply(alphas, labelMat).T*(dataMatrix*dataMatrix[j,:].T))+b\n",
    "                Ej = fXj - float(labelMat[j])\n",
    "                \n",
    "                #为alphaIold，alphaJold分配新的内存，以便观察新旧值的变化\n",
    "                #保存更新前的alpha_i和alpha_j\n",
    "                alphaIold = alphas[i].copy()\n",
    "                alphaJold = alphas[j].copy()\n",
    "                \n",
    "                #计算L,H ，它们用于将alpha[j]的值调整到0和C之间\n",
    "                #如果L和H相等，就不做任何改变，直接执行continue语句，本循环结束直接运行下一次\n",
    "                #步骤2：计算上界和下界：H和L\n",
    "                if (labelMat[i] != labelMat[j]):\n",
    "                    L = max(0, alphas[j] - alphas[i])\n",
    "                    H = min(C, C+alphas[j] - alphas[i])\n",
    "                else:\n",
    "                    L = max(0, alphas[j] + alphas[i] - C)\n",
    "                    H = min(C, alphas[j] + alphas[i])\n",
    "                if (L == H):\n",
    "                    print(\"L == H\")\n",
    "                    continue\n",
    "                \n",
    "                #alpha[j]的最优修改量\n",
    "                #步骤3：计算学习率eta（eta是alpha_j的最优修改量）\n",
    "                eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T -\\\n",
    "                    dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T\n",
    "                if (eta>=0):\n",
    "                    print(\"eta>0\")\n",
    "                    continue\n",
    "                #简化了SMO算法，并计算新的alpha[j]\n",
    "                #步骤4：更新alpha_j\n",
    "                alphas[j] -= labelMat[j]*(Ei - Ej)/eta\n",
    "                #辅助函数调整alpha[j]的值\n",
    "                #步骤5：修剪alpha_j\n",
    "                alphas[j] = clipAlpha(alphas[j],H,L)\n",
    "                \n",
    "                #检查alpha[j]是否有轻微的改变\n",
    "                if (abs(alphas[j] - alphaJold) < 0.00001): print (\"j not moving enough\"); continue\n",
    "                \n",
    "                #alpha[i]和alpha[j]同样进行改变，大小一样，方向相反。\n",
    "                #步骤6，更新alpha_i\n",
    "                alphas[i] += labelMat[j]*labelMat[i]*(alphaJold-alphas[j])\n",
    "                \n",
    "                #alpha优化之后，给这两个值设置一个常数项b\n",
    "                #步骤7：更新b_1,b_2\n",
    "                b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - \\\n",
    "                    labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T\n",
    "                b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - \\\n",
    "                    labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T\n",
    "                #步骤8:根据b_1,b_2更新b\n",
    "                if (0<alphas[i]) and (C>alphas[i]):\n",
    "                    b = b1\n",
    "                elif(0<alphas[j]) and (C > alphas[j]):\n",
    "                    b = b2\n",
    "                else:\n",
    "                    b = (b1 + b2)/2.0\n",
    "                \n",
    "                #执行到for的最后一行都没有执行continue语句，那么就成功的改变了一对alpha，增加计数值   \n",
    "                #统计优化次数\n",
    "                alphaPairsChanged += 1\n",
    "                print(\"iter: %d i:%d, pairs changed %d\" % (iter,i,alphaPairsChanged))\n",
    "        #在for循环之外需要检查alpha的值是否进行了更新\n",
    "        #更新迭代次数\n",
    "        if (alphaPairsChanged == 0): iter += 1\n",
    "        #如果alpha的值更新了则将iter的值设为0后继续运行\n",
    "        else: iter = 0\n",
    "        print (\"iteration number: %d\" % iter)\n",
    "    return b,alphas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 函数说明:计算w\n",
    "# dataMat - 数据矩阵\n",
    "# labelMat - 数据标签\n",
    "# alphas - alphas值\n",
    "#具体的求解方法笔记中有\n",
    "def get_w(dataMat, labelMat, alphas):\n",
    "    alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat)\n",
    "    w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas)\n",
    "    return w.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "函数说明:分类结果可视化\n",
    "\n",
    "Parameters:\n",
    "    dataMat - 数据矩阵\n",
    "    w - 直线法向量\n",
    "    b - 直线解决\n",
    "\"\"\"\n",
    "def showClassifer(dataMat, w, b):\n",
    "    #绘制样本点\n",
    "    data_plus = []                                  #正样本\n",
    "    data_minus = []                                 #负样本\n",
    "    for i in range(len(dataMat)):\n",
    "        if labelMat[i] > 0:\n",
    "            data_plus.append(dataMat[i])\n",
    "        else:\n",
    "            data_minus.append(dataMat[i])\n",
    "    data_plus_np = np.array(data_plus)              #转换为numpy矩阵\n",
    "    data_minus_np = np.array(data_minus)            #转换为numpy矩阵\n",
    "    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1], s=30, alpha=0.7)   #正样本散点图\n",
    "    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7) #负样本散点图\n",
    "    #绘制直线\n",
    "    x1 = max(dataMat)[0]\n",
    "    x2 = min(dataMat)[0]\n",
    "    a1, a2 = w\n",
    "    b = float(b)\n",
    "    a1 = float(a1[0])\n",
    "    a2 = float(a2[0])\n",
    "    y1, y2 = (-b- a1*x1)/a2, (-b - a1*x2)/a2\n",
    "    plt.plot([x1, x2], [y1, y2])\n",
    "    #找出支持向量点\n",
    "    for i, alpha in enumerate(alphas):\n",
    "        if abs(alpha) > 0:\n",
    "            x, y = dataMat[i]\n",
    "            plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red')\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "L == H\n",
      "iter: 0 i:1, pairs changed 1\n",
      "L == H\n",
      "L == H\n",
      "L == H\n",
      "iter: 0 i:5, pairs changed 2\n",
      "L == H\n",
      "L == H\n",
      "iter: 0 i:10, pairs changed 3\n",
      "L == H\n",
      "iter: 0 i:17, pairs changed 4\n",
      "L == H\n",
      "j not moving enough\n",
      "iter: 0 i:22, pairs changed 5\n",
      "iter: 0 i:23, pairs changed 6\n",
      "L == H\n",
      "L == H\n",
      "L == H\n",
      "L == H\n",
      "j not moving enough\n",
      "iter: 0 i:54, pairs changed 7\n",
      "iter: 0 i:55, pairs changed 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "L == H\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:5, pairs changed 1\n",
      "iter: 0 i:10, pairs changed 2\n",
      "j not moving enough\n",
      "iter: 0 i:15, pairs changed 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:19, pairs changed 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "L == H\n",
      "iter: 0 i:29, pairs changed 5\n",
      "iter: 0 i:45, pairs changed 6\n",
      "L == H\n",
      "iter: 0 i:52, pairs changed 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "iter: 0 i:66, pairs changed 8\n",
      "iter: 0 i:75, pairs changed 9\n",
      "j not moving enough\n",
      "iter: 0 i:82, pairs changed 10\n",
      "j not moving enough\n",
      "L == H\n",
      "L == H\n",
      "L == H\n",
      "iter: 0 i:97, pairs changed 11\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:4, pairs changed 1\n",
      "iter: 0 i:5, pairs changed 2\n",
      "iter: 0 i:8, pairs changed 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:17, pairs changed 4\n",
      "j not moving enough\n",
      "iter: 0 i:23, pairs changed 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:43, pairs changed 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:54, pairs changed 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:97, pairs changed 8\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "iter: 0 i:4, pairs changed 1\n",
      "j not moving enough\n",
      "iter: 0 i:8, pairs changed 2\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:57, pairs changed 3\n",
      "L == H\n",
      "j not moving enough\n",
      "iter: 0 i:76, pairs changed 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "iter: 0 i:1, pairs changed 1\n",
      "j not moving enough\n",
      "iter: 0 i:5, pairs changed 2\n",
      "iter: 0 i:7, pairs changed 3\n",
      "j not moving enough\n",
      "L == H\n",
      "iter: 0 i:11, pairs changed 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:24, pairs changed 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:54, pairs changed 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:82, pairs changed 7\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "iter: 0 i:8, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:24, pairs changed 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "iter: 0 i:57, pairs changed 2\n",
      "j not moving enough\n",
      "iter: 0 i:69, pairs changed 3\n",
      "iter: 0 i:82, pairs changed 4\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:55, pairs changed 1\n",
      "iter: 0 i:57, pairs changed 2\n",
      "L == H\n",
      "iter: 0 i:69, pairs changed 3\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:8, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:39, pairs changed 2\n",
      "L == H\n",
      "iter: 0 i:52, pairs changed 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:69, pairs changed 4\n",
      "L == H\n",
      "L == H\n",
      "L == H\n",
      "iteration number: 0\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:57, pairs changed 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:17, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:69, pairs changed 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:10, pairs changed 1\n",
      "iter: 0 i:17, pairs changed 2\n",
      "L == H\n",
      "L == H\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "iter: 0 i:8, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:46, pairs changed 1\n",
      "iter: 0 i:52, pairs changed 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 1 i:76, pairs changed 1\n",
      "j not moving enough\n",
      "L == H\n",
      "L == H\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "L == H\n",
      "L == H\n",
      "iteration number: 0\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:10, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:69, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 2 i:17, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 1 i:29, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 1 i:55, pairs changed 2\n",
      "iter: 1 i:69, pairs changed 3\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 2 i:55, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 4 i:30, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "iter: 12 i:10, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "L == H\n",
      "iter: 0 i:8, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:55, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 1 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "iter: 0 i:10, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 3 i:29, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 3 i:55, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 10 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "iter: 0 i:17, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 1 i:55, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "iter: 14 i:17, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 4 i:55, pairs changed 1\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "iter: 0 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "iter: 12 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 15\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 15 i:55, pairs changed 1\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "iter: 1 i:17, pairs changed 1\n",
      "iter: 1 i:52, pairs changed 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "iter: 2 i:29, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "iter: 0 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 4 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 0 i:55, pairs changed 1\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 15\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 16\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 17\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 18\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 19\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 20\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 20 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 15\n",
      "iter: 15 i:29, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 4 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 15\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 16\n",
      "j not moving enough\n",
      "iter: 16 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "iter: 5 i:29, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 15\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 16\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 17\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 18\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 19\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 20\n",
      "iter: 20 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 12 i:55, pairs changed 1\n",
      "iteration number: 0\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "L == H\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 7 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "iter: 10 i:54, pairs changed 1\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 4 i:55, pairs changed 1\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 15\n",
      "iter: 15 i:29, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iter: 5 i:55, pairs changed 1\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "iter: 11 i:17, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "iter: 0 i:52, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "iter: 2 i:17, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "iter: 13 i:29, pairs changed 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 0\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 1\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 2\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 3\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 4\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 5\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 6\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 7\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 8\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 9\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 10\n",
      "j not moving enough\n",
      "j not moving enough\n",
      "iteration number: 11\n",
      "j not moving enough\n",
      "iteration number: 12\n",
      "j not moving enough\n",
      "iteration number: 13\n",
      "j not moving enough\n",
      "iteration number: 14\n",
      "j not moving enough\n",
      "iteration number: 15\n",
      "j not moving enough\n",
      "iteration number: 16\n",
      "j not moving enough\n",
      "iteration number: 17\n",
      "j not moving enough\n",
      "iteration number: 18\n",
      "j not moving enough\n",
      "iteration number: 19\n",
      "j not moving enough\n",
      "iteration number: 20\n",
      "j not moving enough\n",
      "iteration number: 21\n",
      "j not moving enough\n",
      "iteration number: 22\n",
      "j not moving enough\n",
      "iteration number: 23\n",
      "j not moving enough\n",
      "iteration number: 24\n",
      "j not moving enough\n",
      "iteration number: 25\n",
      "j not moving enough\n",
      "iteration number: 26\n",
      "j not moving enough\n",
      "iteration number: 27\n",
      "j not moving enough\n",
      "iteration number: 28\n",
      "j not moving enough\n",
      "iteration number: 29\n",
      "j not moving enough\n",
      "iteration number: 30\n",
      "j not moving enough\n",
      "iteration number: 31\n",
      "j not moving enough\n",
      "iteration number: 32\n",
      "j not moving enough\n",
      "iteration number: 33\n",
      "j not moving enough\n",
      "iteration number: 34\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "j not moving enough\n",
      "iteration number: 35\n",
      "j not moving enough\n",
      "iteration number: 36\n",
      "j not moving enough\n",
      "iteration number: 37\n",
      "j not moving enough\n",
      "iteration number: 38\n",
      "j not moving enough\n",
      "iteration number: 39\n",
      "j not moving enough\n",
      "iteration number: 40\n",
      "Wall time: 2.48 s\n"
     ]
    }
   ],
   "source": [
    "%time b,alphas=smoSimple(dataMat, labelMat, 0.6, 0.001, 40)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[-3.82362484]])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[0.12675129, 0.24014895, 0.36690024]])"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "alphas[alphas>0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[0.8103140110814655], [-0.27113351168312727]]"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w=get_w(dataMat, labelMat, alphas)\n",
    "w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# b,alphas = smoSimple(dataMat, labelMat, 0.6, 0.001, 40)\n",
    "# w = get_w(dataMat, labelMat, alphas)\n",
    "showClassifer(dataMat, w, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "#完整版Platt SMO算法\n",
    "# -*-coding:utf-8 -*-\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import random\n",
    "\n",
    "class optStruct:\n",
    "    \"\"\"\n",
    "    数据结构，维护所有需要操作的值\n",
    "    Parameters：\n",
    "        dataMatIn - 数据矩阵\n",
    "        classLabels - 数据标签\n",
    "        C - 松弛变量\n",
    "        toler - 容错率\n",
    "    \"\"\"\n",
    "    def __init__(self, dataMatIn, classLabels, C, toler):\n",
    "        self.X = dataMatIn#数据矩阵\n",
    "        self.labelMat = classLabels#数据标签\n",
    "        self.C = C #松弛变量\n",
    "        self.tol = toler #容错率\n",
    "        self.m = np.shape(dataMatIn)[0]#数据矩阵行数\n",
    "        self.alphas = np.mat(np.zeros((self.m,1)))#根据矩阵行数初始化alpha参数为0   \n",
    "        self.b = 0#初始化b参数为0\n",
    "        #根据矩阵行数初始化误差缓存，第一列为是否有效的标志位，第二列为实际的误差E的值。\n",
    "        self.eCache = np.mat(np.zeros((self.m,2)))\n",
    "\n",
    "def loadDataSet(fileName):\n",
    "    \"\"\"\n",
    "    读取数据\n",
    "    Parameters:\n",
    "        fileName - 文件名\n",
    "    Returns:\n",
    "        dataMat - 数据矩阵\n",
    "        labelMat - 数据标签\n",
    "    \"\"\"\n",
    "    dataMat = []; labelMat = []\n",
    "    fr = open(fileName)\n",
    "    for line in fr.readlines():#逐行读取，滤除空格等\n",
    "        lineArr = line.strip().split('\\t')\n",
    "        dataMat.append([float(lineArr[0]), float(lineArr[1])])#添加数据\n",
    "        labelMat.append(float(lineArr[2]))#添加标签\n",
    "    return dataMat,labelMat\n",
    "\n",
    "def calcEk(oS, k):\n",
    "    \"\"\"\n",
    "    计算误差\n",
    "    Parameters：\n",
    "        oS - 数据矩阵\n",
    "        k - 标号为k的数据\n",
    "    Returns:\n",
    "        Ek - 标号为k的数据误差\n",
    "    \"\"\"\n",
    "    fXk = float(np.multiply(oS.alphas,oS.labelMat).T*(oS.X*oS.X[k,:].T) + oS.b)\n",
    "    Ek = fXk - float(oS.labelMat[k])\n",
    "    return Ek\n",
    "\n",
    "def selectJrand(i, m):\n",
    "    \"\"\"\n",
    "    函数说明:随机选择alpha_j的索引值\n",
    "\n",
    "    Parameters:\n",
    "        i - alpha_i的索引值\n",
    "        m - alpha参数个数\n",
    "    Returns:\n",
    "        j - alpha_j的索引值\n",
    "    \"\"\"\n",
    "    j = i                                 #选择一个不等于i的j\n",
    "    while (j == i):\n",
    "        j = int(random.uniform(0, m))\n",
    "    return j"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "#platt-smo重点\n",
    "#在选择第2个alphas参数时（也就是进行SMO的内循环时），不再是随机选择，而是选择最长步长的那个（就是选择|E_i-Ej|最大的）\n",
    "#建立一个全局的缓存用于保存误差值\n",
    "def selectJ(i, oS, Ei):\n",
    "    \"\"\"\n",
    "    内循环启发方式2\n",
    "    Parameters：\n",
    "        i - 标号为i的数据的索引值\n",
    "        oS - 数据结构\n",
    "        Ei - 标号为i的数据误差\n",
    "    Returns:\n",
    "        j, maxK - 标号为j或maxK的数据的索引值\n",
    "        Ej - 标号为j的数据误差\n",
    "    \"\"\"\n",
    "    maxK = -1; maxDeltaE = 0; Ej = 0                         #初始化\n",
    "    # 首先将输入值Ei在缓存中设置成为有效的。这里的有效意味着它已经计算好了。\n",
    "    oS.eCache[i] = [1,Ei]                                      #根据Ei更新误差缓存\n",
    "    \n",
    "#     print ('oS.eCache[%s]=%s'%(i,oS.eCache[i]))\n",
    "#     oS.eCache[1]=[[1. 1.]]\n",
    "#     oS.eCache[2]=[[ 1. -1.]]\n",
    "#     oS.eCache[3]=[[1.         0.09242071]]\n",
    "    \n",
    "    \n",
    "    \n",
    "    # print 'oS.eCache[:, 0].A=%s' % oS.eCache[:, 0].A.T\n",
    "    # \"\"\"\n",
    "    # # 返回非0的：行列值\n",
    "    # nonzero(oS.eCache[:, 0].A)= (\n",
    "    #     行： array([ 0,  2,  4,  5,  8, 10, 17, 18, 20, 21, 23, 25, 26, 29, 30, 39, 46,52, 54, 55, 62, 69, 70, \n",
    "    #           76, 79, 82, 94, 97]), \n",
    "    #     列： array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0])\n",
    "    # )\n",
    "    # \"\"\"\n",
    "    # print 'nonzero(oS.eCache[:, 0].A)=', nonzero(oS.eCache[:, 0].A)\n",
    "    # # 取行的list\n",
    "    # print 'nonzero(oS.eCache[:, 0].A)[0]=', nonzero(oS.eCache[:, 0].A)[0]\n",
    "    \n",
    "    \n",
    "    \n",
    "    \n",
    "    # 非零E值的行的list列表，所对应的alpha值\n",
    "    validEcacheList = np.nonzero(oS.eCache[:,0].A)[0]        #返回误差不为0的数据的索引值\n",
    "#     print(\"validEcacheList\",validEcacheList)\n",
    "#     validEcacheList [0]\n",
    "#     validEcacheList [ 0  2  4 90]\n",
    "#     validEcacheList [ 0  2  4  5 90]\n",
    "\n",
    "#选择最大的步长|E_i-Ej|的j作为作为alphas_j\n",
    "    if (len(validEcacheList)) > 1:                            #有不为0的误差\n",
    "        for k in validEcacheList:                           #遍历,找到最大的Ek\n",
    "            if k == i: continue                             #不计算i,浪费时间\n",
    "            Ek = calcEk(oS, k)                                #计算Ek\n",
    "            deltaE = abs(Ei - Ek)                            #计算|Ei-Ek|\n",
    "            if (deltaE > maxDeltaE):                        #找到maxDeltaE\n",
    "                maxK = k; maxDeltaE = deltaE; Ej = Ek\n",
    "        return maxK, Ej                                        #返回maxK,Ej\n",
    "    else:                                                   #没有不为0的误差\n",
    "        j = selectJrand(i, oS.m)                            #随机选择alpha_j的索引值\n",
    "        Ej = calcEk(oS, j)                                    #计算Ej\n",
    "    return j, Ej                                             #j,Ej"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "def updateEk(oS, k):\n",
    "    \"\"\"\n",
    "    计算Ek,并更新误差缓存\n",
    "    Parameters：\n",
    "        oS - 数据结构\n",
    "        k - 标号为k的数据的索引值\n",
    "    Returns:\n",
    "        无\n",
    "    \"\"\"\n",
    "    Ek = calcEk(oS, k)                                        #计算Ek\n",
    "    oS.eCache[k] = [1,Ek]                                    #更新误差缓存\n",
    "\n",
    "\n",
    "def clipAlpha(aj,H,L):\n",
    "    \"\"\"\n",
    "    修剪alpha_j\n",
    "    Parameters:\n",
    "        aj - alpha_j的值\n",
    "        H - alpha上限\n",
    "        L - alpha下限\n",
    "    Returns:\n",
    "        aj - 修剪后的alpah_j的值\n",
    "    \"\"\"\n",
    "    if aj > H:\n",
    "        aj = H\n",
    "    if L > aj:\n",
    "        aj = L\n",
    "    return aj"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "#更新b并且返回两个alpha参数是否改变的情况，内循环\n",
    "def innerL(i, oS):\n",
    "    \"\"\"\n",
    "    优化的SMO算法\n",
    "    Parameters：\n",
    "        i - 标号为i的数据的索引值\n",
    "        oS - 数据结构\n",
    "    Returns:\n",
    "        1 - 有任意一对alpha值发生变化\n",
    "        0 - 没有任意一对alpha值发生变化或变化太小\n",
    "    \"\"\"\n",
    "    #步骤1：计算误差Ei\n",
    "    Ei = calcEk(oS, i)\n",
    "    \n",
    "    # 约束条件 (KKT条件是解决最优化问题的时用到的一种方法。我们这里提到的最优化问题通常是指对于给定的某一函数，\n",
    "    #求其在指定作用域上的全局最小值)\n",
    "    # 0<=alphas[i]<=C，但由于0和C是边界值，我们无法进行优化，因为需要增加一个alphas和降低一个alphas。\n",
    "    # 表示发生错误的概率：labelMat[i]*Ei 如果超出了 toler， 才需要优化。至于正负号，我们考虑绝对值就对了。\n",
    "    '''\n",
    "    # 检验训练样本(xi, yi)是否满足KKT条件\n",
    "    yi*f(i) >= 1 and alpha = 0 (outside the boundary)\n",
    "    yi*f(i) == 1 and 0<alpha< C (on the boundary)\n",
    "    yi*f(i) <= 1 and alpha = C (between the boundary)\n",
    "    '''\n",
    "    \n",
    "    #优化alpha,设定一定的容错率。\n",
    "    if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or \\\n",
    "        ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)):\n",
    "        #使用内循环启发方式2选择alpha_j,并计算Ej\n",
    "        j,Ej = selectJ(i, oS, Ei)\n",
    "        #保存更新前的aplpha值，使用深拷贝\n",
    "        alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy();\n",
    "        #步骤2：计算上下界L和H\n",
    "        if (oS.labelMat[i] != oS.labelMat[j]):\n",
    "            L = max(0, oS.alphas[j] - oS.alphas[i])\n",
    "            H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])\n",
    "        else:\n",
    "            L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C)\n",
    "            H = min(oS.C, oS.alphas[j] + oS.alphas[i])\n",
    "        if L == H:\n",
    "            print(\"L==H\")\n",
    "            return 0\n",
    "        #步骤3：计算eta\n",
    "        eta = 2.0 * oS.X[i,:] * oS.X[j,:].T - oS.X[i,:] * oS.X[i,:].T - oS.X[j,:] * oS.X[j,:].T\n",
    "        if eta >= 0:\n",
    "            print(\"eta>=0\")\n",
    "            return 0\n",
    "        #步骤4：更新alpha_j\n",
    "        oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej)/eta\n",
    "        #步骤5：修剪alpha_j\n",
    "        oS.alphas[j] = clipAlpha(oS.alphas[j],H,L)\n",
    "        #更新Ej至误差缓存\n",
    "        updateEk(oS, j)\n",
    "        if (abs(oS.alphas[j] - alphaJold) < 0.00001):\n",
    "            print(\"alpha_j变化太小\")\n",
    "            return 0\n",
    "        #步骤6：更新alpha_i\n",
    "        oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j])\n",
    "        #更新Ei至误差缓存\n",
    "        updateEk(oS, i)\n",
    "        #步骤7：更新b_1和b_2\n",
    "        b1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.X[i,:]*oS.X[i,:].T \\\n",
    "            - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[i,:]*oS.X[j,:].T\n",
    "        b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.X[i,:]*oS.X[j,:].T \\\n",
    "            - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[j,:]*oS.X[j,:].T\n",
    "        #步骤8：根据b_1和b_2更新b\n",
    "        if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1\n",
    "        elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2\n",
    "        else: oS.b = (b1 + b2)/2.0\n",
    "        return 1\n",
    "    else:\n",
    "        return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "def showClassifer(dataMat, classLabels, w, b):\n",
    "    \"\"\"\n",
    "    分类结果可视化\n",
    "    Parameters:\n",
    "        dataMat - 数据矩阵\n",
    "        w - 直线法向量\n",
    "        b - 直线解决\n",
    "    Returns:\n",
    "        无\n",
    "    \"\"\"\n",
    "    #绘制样本点\n",
    "    data_plus = []                                  #正样本\n",
    "    data_minus = []                                 #负样本\n",
    "    for i in range(len(dataMat)):\n",
    "        if classLabels[i] > 0:\n",
    "            data_plus.append(dataMat[i])\n",
    "        else:\n",
    "            data_minus.append(dataMat[i])\n",
    "    data_plus_np = np.array(data_plus)              #转换为numpy矩阵\n",
    "    data_minus_np = np.array(data_minus)            #转换为numpy矩阵\n",
    "    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1], s=30, alpha=0.7)   #正样本散点图\n",
    "    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7) #负样本散点图\n",
    "    #绘制直线\n",
    "    x1 = max(dataMat)[0]\n",
    "    x2 = min(dataMat)[0]\n",
    "    a1, a2 = w\n",
    "    b = float(b)\n",
    "    a1 = float(a1[0])\n",
    "    a2 = float(a2[0])\n",
    "    y1, y2 = (-b- a1*x1)/a2, (-b - a1*x2)/a2\n",
    "    plt.plot([x1, x2], [y1, y2])\n",
    "    #找出支持向量点\n",
    "    for i, alpha in enumerate(alphas):\n",
    "        if abs(alpha) > 0:\n",
    "            x, y = dataMat[i]\n",
    "            plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red')\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "def calcWs(alphas,dataArr,classLabels):\n",
    "    \"\"\"\n",
    "    计算w\n",
    "    Parameters:\n",
    "        dataArr - 数据矩阵\n",
    "        classLabels - 数据标签\n",
    "        alphas - alphas值\n",
    "    Returns:\n",
    "        w - 计算得到的w\n",
    "    \"\"\"\n",
    "    X = np.mat(dataArr); labelMat = np.mat(classLabels).transpose()\n",
    "    m,n = np.shape(X)\n",
    "    w = np.zeros((n,1))\n",
    "    for i in range(m):\n",
    "        w += np.multiply(alphas[i]*labelMat[i],X[i,:].T)\n",
    "    return w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "def smoP(dataMatIn, classLabels, C, toler, maxIter):\n",
    "    \n",
    "    \"\"\"\n",
    "    完整SMO算法外循环，与smoSimple有些类似，但这里的循环退出条件更多一些\n",
    "    Args:\n",
    "        dataMatIn    数据集\n",
    "        classLabels  类别标签\n",
    "        C   松弛变量(常量值)，允许有些数据点可以处于分隔面的错误一侧。\n",
    "            控制最大化间隔和保证大部分的函数间隔小于1.0这两个目标的权重。\n",
    "            可以通过调节该参数达到不同的结果。\n",
    "        toler   容错率\n",
    "        maxIter 退出前最大的循环次数\n",
    "    Returns:\n",
    "        b       模型的常量值\n",
    "        alphas  拉格朗日乘子\n",
    "    \"\"\"   \n",
    "    \"\"\"\n",
    "    完整的线性SMO算法\n",
    "    Parameters：\n",
    "        dataMatIn - 数据矩阵\n",
    "        classLabels - 数据标签\n",
    "        C - 松弛变量\n",
    "        toler - 容错率\n",
    "        maxIter - 最大迭代次数\n",
    "    Returns:\n",
    "        oS.b - SMO算法计算的b\n",
    "        oS.alphas - SMO算法计算的alphas\n",
    "    \"\"\"\n",
    "    oS = optStruct(np.mat(dataMatIn), np.mat(classLabels).transpose(), C, toler)#初始化数据结构\n",
    "    iter = 0#初始化当前迭代次数\n",
    "    # 违反 KKT 条件的标志符\n",
    "    entireSet = True\n",
    "    # 迭代中优化的次数\n",
    "    alphaPairsChanged = 0\n",
    "    #遍历整个数据集都alpha也没有更新或者超过最大迭代次数,则退出循环\n",
    "    while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):\n",
    "        alphaPairsChanged = 0\n",
    "        #print(\"oS.m\",oS.m)\n",
    "        if entireSet:#遍历整个数据集                           \n",
    "            for i in range(oS.m):       \n",
    "                alphaPairsChanged += innerL(i,oS)#使用优化的SMO算法\n",
    "                print(\"全样本遍历:第%d次迭代 样本:%d, alpha优化次数:%d\" % (iter,i,alphaPairsChanged))\n",
    "            iter += 1\n",
    "        # 对已存在 alpha对，选出非边界的alpha值，进行优化。\n",
    "        else: #遍历非边界值\n",
    "            # 遍历所有的非边界alpha值，也就是不在边界0或C上的值。\n",
    "            nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0]#遍历不在边界0和C的alpha\n",
    "#             print(\"nonBoundIs\",nonBoundIs)\n",
    "#             nonBoundIs [ 0  3  4 17 18 25 46 55 94]\n",
    "            for i in nonBoundIs:\n",
    "                alphaPairsChanged += innerL(i,oS)\n",
    "                print(\"非边界遍历:第%d次迭代 样本:%d, alpha优化次数:%d\" % (iter,i,alphaPairsChanged))\n",
    "            iter += 1\n",
    "        if entireSet:#遍历一次后改为非边界遍历\n",
    "            entireSet = False\n",
    "        elif (alphaPairsChanged == 0):#如果alpha没有更新,计算全样本遍历\n",
    "            entireSet = True \n",
    "        print(\"迭代次数: %d\" % iter)\n",
    "    return oS.b,oS.alphas #返回SMO算法计算的b和alphas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "L==H\n",
      "全样本遍历:第0次迭代 样本:0, alpha优化次数:0\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:1, alpha优化次数:0\n",
      "全样本遍历:第0次迭代 样本:2, alpha优化次数:1\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:3, alpha优化次数:1\n",
      "全样本遍历:第0次迭代 样本:4, alpha优化次数:2\n",
      "全样本遍历:第0次迭代 样本:5, alpha优化次数:2\n",
      "全样本遍历:第0次迭代 样本:6, alpha优化次数:2\n",
      "alpha_j变化太小\n",
      "全样本遍历:第0次迭代 样本:7, alpha优化次数:2\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:8, alpha优化次数:2\n",
      "全样本遍历:第0次迭代 样本:9, alpha优化次数:2\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:10, alpha优化次数:2\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:11, alpha优化次数:2\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:12, alpha优化次数:2\n",
      "全样本遍历:第0次迭代 样本:13, alpha优化次数:2\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:14, alpha优化次数:2\n",
      "全样本遍历:第0次迭代 样本:15, alpha优化次数:2\n",
      "全样本遍历:第0次迭代 样本:16, alpha优化次数:2\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:17, alpha优化次数:2\n",
      "全样本遍历:第0次迭代 样本:18, alpha优化次数:3\n",
      "全样本遍历:第0次迭代 样本:19, alpha优化次数:3\n",
      "全样本遍历:第0次迭代 样本:20, alpha优化次数:3\n",
      "全样本遍历:第0次迭代 样本:21, alpha优化次数:3\n",
      "alpha_j变化太小\n",
      "全样本遍历:第0次迭代 样本:22, alpha优化次数:3\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:23, alpha优化次数:3\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:24, alpha优化次数:3\n",
      "全样本遍历:第0次迭代 样本:25, alpha优化次数:4\n",
      "alpha_j变化太小\n",
      "全样本遍历:第0次迭代 样本:26, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:27, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:28, alpha优化次数:4\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:29, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:30, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:31, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:32, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:33, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:34, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:35, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:36, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:37, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:38, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:39, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:40, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:41, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:42, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:43, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:44, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:45, alpha优化次数:4\n",
      "全样本遍历:第0次迭代 样本:46, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:47, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:48, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:49, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:50, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:51, alpha优化次数:5\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:52, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:53, alpha优化次数:5\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:54, alpha优化次数:5\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:55, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:56, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:57, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:58, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:59, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:60, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:61, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:62, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:63, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:64, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:65, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:66, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:67, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:68, alpha优化次数:5\n",
      "L==H\n",
      "全样本遍历:第0次迭代 样本:69, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:70, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:71, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:72, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:73, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:74, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:75, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:76, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:77, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:78, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:79, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:80, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:81, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:82, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:83, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:84, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:85, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:86, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:87, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:88, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:89, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:90, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:91, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:92, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:93, alpha优化次数:5\n",
      "全样本遍历:第0次迭代 样本:94, alpha优化次数:6\n",
      "全样本遍历:第0次迭代 样本:95, alpha优化次数:6\n",
      "全样本遍历:第0次迭代 样本:96, alpha优化次数:6\n",
      "alpha_j变化太小\n",
      "全样本遍历:第0次迭代 样本:97, alpha优化次数:6\n",
      "全样本遍历:第0次迭代 样本:98, alpha优化次数:6\n",
      "全样本遍历:第0次迭代 样本:99, alpha优化次数:6\n",
      "迭代次数: 1\n",
      "alpha_j变化太小\n",
      "非边界遍历:第1次迭代 样本:0, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "非边界遍历:第1次迭代 样本:3, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "非边界遍历:第1次迭代 样本:4, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "非边界遍历:第1次迭代 样本:17, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "非边界遍历:第1次迭代 样本:18, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "非边界遍历:第1次迭代 样本:25, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "非边界遍历:第1次迭代 样本:46, alpha优化次数:0\n",
      "非边界遍历:第1次迭代 样本:55, alpha优化次数:0\n",
      "非边界遍历:第1次迭代 样本:94, alpha优化次数:0\n",
      "迭代次数: 2\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:0, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:1, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:2, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:3, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:4, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:5, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:6, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:7, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:8, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:9, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:10, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:11, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:12, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:13, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:14, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:15, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:16, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:17, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:18, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:19, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:20, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:21, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:22, alpha优化次数:0\n",
      "L==H\n",
      "全样本遍历:第2次迭代 样本:23, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:24, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:25, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:26, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:27, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:28, alpha优化次数:0\n",
      "L==H\n",
      "全样本遍历:第2次迭代 样本:29, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:30, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:31, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:32, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:33, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:34, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:35, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:36, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:37, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:38, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:39, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:40, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:41, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:42, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:43, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:44, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:45, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:46, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:47, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:48, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:49, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:50, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:51, alpha优化次数:0\n",
      "L==H\n",
      "全样本遍历:第2次迭代 样本:52, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:53, alpha优化次数:0\n",
      "L==H\n",
      "全样本遍历:第2次迭代 样本:54, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:55, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:56, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:57, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:58, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:59, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:60, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:61, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:62, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:63, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:64, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:65, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:66, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:67, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:68, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:69, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:70, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:71, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:72, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:73, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:74, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:75, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:76, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:77, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:78, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:79, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:80, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:81, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:82, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:83, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:84, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:85, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:86, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:87, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:88, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:89, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:90, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:91, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:92, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:93, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:94, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:95, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:96, alpha优化次数:0\n",
      "alpha_j变化太小\n",
      "全样本遍历:第2次迭代 样本:97, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:98, alpha优化次数:0\n",
      "全样本遍历:第2次迭代 样本:99, alpha优化次数:0\n",
      "迭代次数: 3\n",
      "Wall time: 65.8 ms\n"
     ]
    }
   ],
   "source": [
    "dataArr, classLabels = loadDataSet('testSet.txt')\n",
    "%time b, alphas = smoP(dataArr, classLabels, 0.6, 0.001, 40)\n",
    "w = calcWs(alphas,dataArr, classLabels) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    " showClassifer(dataArr, classLabels, w, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x1b9c98c4e88>"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "from pandas import Series,DataFrame\n",
    "# 如果不添加该行，则每次显示图片都需要加上plt.show\n",
    "%matplotlib inline\n",
    "d=plt.imread('jielun.png')\n",
    "plt.imshow(d)\n"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "图中画红圈的样本点为支持向量上的点，是满足算法的一种解。完整版SMO算法覆盖整个数据集进行计算，而简化版SMO算法是随机选择的。可以看出，完整版SMO算法选出的支持向量样点更多，更接近理想的分隔超平面。\n",
    "\n",
    "对比两种算法的运算时间，我的测试结果是完整版SMO算法的速度比简化版SMO算法的速度快6倍左右。\n",
    "\n",
    "其实，优化方法不仅仅是简单的启发式选择，还有其他优化方法，SMO算法速度还可以进一步提高。"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "全样本遍历:第0次迭代 样本:0, alpha优化次数:1\n",
    "全样本遍历:第0次迭代 样本:1, alpha优化次数:1\n",
    "全样本遍历:第0次迭代 样本:2, alpha优化次数:2\n",
    "全样本遍历:第0次迭代 样本:3, alpha优化次数:3\n",
    "L==H\n",
    "全样本遍历:第0次迭代 样本:4, alpha优化次数:3\n",
    "L==H\n",
    "全样本遍历:第0次迭代 样本:5, alpha优化次数:3\n",
    "L==H\n",
    "全样本遍历:第0次迭代 样本:6, alpha优化次数:3\n",
    "全样本遍历:第0次迭代 样本:7, alpha优化次数:4\n",
    "alpha_j变化太小\n",
    "全样本遍历:第0次迭代 样本:8, alpha优化次数:4\n",
    "`````\n",
    "全样本遍历:第0次迭代 样本:41, alpha优化次数:6\n",
    "````\n",
    "全样本遍历:第0次迭代 样本:50, alpha优化次数:6\n",
    "全样本遍历:第0次迭代 样本:51, alpha优化次数:6\n",
    "L==H\n",
    "全样本遍历:第0次迭代 样本:52, alpha优化次数:6\n",
    "全样本遍历:第0次迭代 样本:53, alpha优化次数:6\n",
    "L==H\n",
    "全样本遍历:第0次迭代 样本:54, alpha优化次数:6\n",
    "L==H\n",
    "全样本遍历:第0次迭代 样本:55, alpha优化次数:6\n",
    "```\n",
    "全样本遍历:第0次迭代 样本:66, alpha优化次数:6\n",
    "```````\n",
    "全样本遍历:第0次迭代 样本:96, alpha优化次数:6\n",
    "全样本遍历:第0次迭代 样本:97, alpha优化次数:6\n",
    "全样本遍历:第0次迭代 样本:98, alpha优化次数:6\n",
    "全样本遍历:第0次迭代 样本:99, alpha优化次数:6\n",
    "迭代次数: 1\n",
    "非边界遍历:第1次迭代 样本:0, alpha优化次数:1\n",
    "alpha_j变化太小\n",
    "非边界遍历:第1次迭代 样本:2, alpha优化次数:1\n",
    "alpha_j变化太小\n",
    "非边界遍历:第1次迭代 样本:6, alpha优化次数:1\n",
    "alpha_j变化太小\n",
    "非边界遍历:第1次迭代 样本:7, alpha优化次数:1\n",
    "alpha_j变化太小\n",
    "非边界遍历:第1次迭代 样本:10, alpha优化次数:1\n",
    "alpha_j变化太小\n",
    "非边界遍历:第1次迭代 样本:18, alpha优化次数:1\n",
    "alpha_j变化太小\n",
    "非边界遍历:第1次迭代 样本:23, alpha优化次数:1\n",
    "迭代次数: 2\n",
    "非边界遍历:第2次迭代 样本:0, alpha优化次数:0\n",
    "alpha_j变化太小\n",
    "非边界遍历:第2次迭代 样本:2, alpha优化次数:0\n",
    "alpha_j变化太小\n",
    "非边界遍历:第2次迭代 样本:6, alpha优化次数:0\n",
    "```````\n",
    "全样本遍历:第3次迭代 样本:99, alpha优化次数:0\n",
    "迭代次数: 4\n",
    "Wall time: 79.8 ms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
